package github.ziwukun.jsonql.lang;

import static github.ziwukun.jsonql.lang.CmpOpr.*;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;

/**
 * where 语句 json相关
 * @author Hugo.Yu
 */
class WhereJson {
	
	/**
	 * 从JSON对象的字符串中创建一个Where<br>
	 * JSON语法形如:<br>
	 * ```json
	 * {
	 * 		"name":"张三",
	 * 		"article":{
	 * 			"title":{
	 * 				"@like":"好消息"
	 * 			},
	 * 			"comment":{
	 * 				"author":{
	 * 					"name":"李四"			
	 * 				}
	 * 			}
	 * 		}
	 * }
	 * ```
	 */
	static Where readJson(String json) {
		if(StrUtil.isBlank(json)) {
			throw new JsonQLFormatException("创建@where失败，JSON字符串对象不能为空",
				"@where语句语法错误:JSON对象不能为空");
		}
		
		// 转换成JSON对象方便解析
		// 对入参进行检查
		JSONObject jsonObject = new JSONObject(json);
		Set<String> keys = jsonObject.keySet();
		if(keys.size() == 0) {
			throw new JsonQLFormatException("创建WhereQL失败，WhereQL至少要有一个条件设置",
				"@WHERE语句语法错误-" + json);
		}
		
		// 如果JSON对象是一个多key的对象，那么就默认为@and链接
		// 使用@and条件进行包装
		if(keys.size() != 1) {
			jsonObject = new JSONObject();
			jsonObject.set(CmpOpr.AND.atWord(), new JSONObject(json));
		}
		
		// 获取key和value值
		String key = jsonObject.keySet().iterator().next();
		Object value = jsonObject.get(key);
		if(value == null) {
			throw new JsonQLFormatException("创建WhereQL失败，val值不能为null",
				"@WHERE语句语法错误-" + json);
		}
		
		// key为条件关键字时使用条件关键字的处理方式
		if(isCmpOpr(key)) {
			CmpOpr conditionKey = valOf(key);
			return new WhereImpl(key,
				conditionKey.getVal(jsonObject.toString()));
		}
		
		if(key.startsWith("@")) {
			throw new JsonQLFormatException("创建WhereQL失败，" + key + "为不合法的条件符号", 
				"@WHERE语句语法错误-" + json);
		}
		
		// key不是条件关键字，就是普通字段
		// key值为普通字段时，value值有3种情况
		// 1 value为普通值，字符串或数字类型，此时是使用等值比较
		if((value instanceof Number) || value instanceof String) {
			return new WhereImpl(key, 
				new WhereImpl(CmpOpr.EQ.atWord(),(Serializable)value));
		}
		// 2 为JSON对象，递归使用此方法创建即可
		if(value instanceof JSONObject) {
			return new WhereImpl(key,WhereJson.readJson(value.toString()));
		}
		// 3 为JSONArray对象，默认为IN查询
		if(value instanceof JSONArray) {
			JSONObject newConditionJson = new JSONObject();
			newConditionJson.set(CmpOpr.IN.atWord(), value);
			return new WhereImpl(key,CmpOpr.IN.getVal(newConditionJson.toString()));
		}
		throw new JsonQLFormatException(key + "的值类型为未知的数据类型，请检查" + value,
			"@WHERE语句语法错误-" + json);
	}
	
	static String writeJson(WhereImpl where) {
		JSONObject json = new JSONObject();
		if(StrUtil.isBlank(where.key())) {
			return json.toString();
		}
		
		// 值是普通类型时，直接添加
		if(where.val instanceof String || where.val instanceof Number 
			|| where.val instanceof Boolean) {
			json.set(where.key,where.val);
			return json.toString();
		}
		
		// 值是JsonQLWhere，使用递归
		if(where.val instanceof WhereImpl) {
			String s = ((WhereImpl)where.val).toJSONQL();
			json.set(where.key, new JSONObject(s));
			return json.toString();
		}
		
		// 如果值是数组类型，判断每个元素的类型，分别添加
		if (where.val instanceof Collection) {
			JSONArray jsonArray = new JSONArray();
			for (Iterator<?> iterator = ((Collection<?>) where.val).iterator(); 
				iterator.hasNext();) {
				Object valueItem = iterator.next();
				// 值是普通类型时，直接添加
				if (valueItem instanceof String || valueItem instanceof Number) {
					jsonArray.add(valueItem);
				}
				// 值是JsonQLWhere，使用递归
				if (valueItem instanceof WhereImpl) {
					jsonArray.add(new JSONObject(((WhereImpl)valueItem).toJSONQL()));
				}
			}
			
			JSONObject obj = new JSONObject();
			obj.set(where.key, jsonArray);
			return obj.toString();
		}
		
		throw new RuntimeException("未知值类型错误");
	}
}
